package com.salon.server;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.salon.client.ServiceException;
import com.salon.client.beans.MasterBean;
import com.salon.client.beans.ProcedureBean;
import com.salon.client.beans.WorkDayBean;
import com.salon.server.db.DBUtils;

public class WorkDayManager {
	private static WorkDayManager wdManager;
	public static final Logger LOG = Logger.getLogger(WorkDayManager.class);
	
	public static WorkDayManager getInstance() {
		if (wdManager == null) {
			wdManager = new WorkDayManager();
		}
		
		return wdManager;
	}
	
	
	public List<WorkDayBean> getWorkDays(int year, int month) throws ServiceException {
		List<WorkDayBean> list = new ArrayList<WorkDayBean>();
		List<MasterBean> masters = DBUtils.getInstance().loadMasters(null);
		
		Calendar sdate = Calendar.getInstance();
		sdate.set(Calendar.YEAR, year);
		sdate.set(Calendar.MONTH, month);
		sdate.set(Calendar.DAY_OF_MONTH, 1);
		
		Calendar fdate = Calendar.getInstance();
		fdate.set(Calendar.YEAR, year);
		fdate.set(Calendar.MONTH, month + 1);
		fdate.set(Calendar.DAY_OF_MONTH, 1);
		
		for (MasterBean master : masters) {
			List<Date> dates = DBUtils.getInstance().loadWorkDayForMaster(master.getId(), 
					sdate.getTime(), fdate.getTime());
			Map<Date, Integer> map = DBUtils.getInstance().loadProcedureCostForMaster(master.getId(), 
					sdate.getTime(), fdate.getTime());
			
			WorkDayBean workBean = new WorkDayBean();
			workBean.setMasterId(master.getId());
			workBean.setMasterName(master.getMasterName());
			
			List<Boolean> dayMonth = getDays(year, month);
			for (Date date : dates) {
				if (date.getDate() - 1 < dayMonth.size()) {
					dayMonth.set(date.getDate() - 1, true);
				}
			}
			
			List<Integer> costMounth = getCosts(year, month);
			for (Date date : map.keySet()) {
				if (date.getDate() - 1 < costMounth.size()) {
					costMounth.set(date.getDate() - 1, map.get(date));
				}
			}
			
			workBean.setList(dayMonth);
			workBean.setCosts(costMounth);
			
			list.add(workBean);
		}
		
		return list;
	}
	
	private List<Boolean> getDays(int year, int month) {
		List<Boolean> list = new ArrayList<Boolean>();
		int i = 0;
		while (i ++ < getDaysCount(year, month)) {
			list.add(false);
		}
		return list;
			
	}
	
	private List<Integer> getCosts(int year, int month) {
		List<Integer> list = new ArrayList<Integer>();
		int i = 0;
		while (i ++ < getDaysCount(year, month)) {
			list.add(0);
		}
		return list;
			
	}
	
	public void addWorkDay(int masterId, int day, int month, int year) throws ServiceException {
		Calendar sdate = Calendar.getInstance();
		sdate.set(Calendar.YEAR, year);
		sdate.set(Calendar.MONTH, month);
		sdate.set(Calendar.DAY_OF_MONTH, day);
		
		DBUtils.getInstance().addWorkDay(masterId, sdate.getTime());
	}
	
	public void deleteWorkDay(int masterId, int day, int month, int year) throws ServiceException {
		Calendar sdate = Calendar.getInstance();
		sdate.set(Calendar.YEAR, year);
		sdate.set(Calendar.MONTH, month);
		sdate.set(Calendar.DAY_OF_MONTH, day);
		
		DBUtils.getInstance().deleteWorkDay(masterId, sdate.getTime());
	}
	
	private int getDaysCount(int year, int month) {
		if (month != 1) {
			if (month < 7) {
				return (month % 2) == 0 ? 31 : 30;
			}
			else {
				return (month % 2) == 1 ? 31 : 30;
			}
		}
		else {
			return ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)) ? 29 : 28;
		}
	}
	
	public Map<Date, Map<MasterBean, ProcedureBean>> getProceduresForDay(Date date, int offset) throws ServiceException {
		Calendar cal = Calendar.getInstance();
		cal.setTime(date);
		cal.add(Calendar.DAY_OF_MONTH, offset);
		date = cal.getTime();
		
		Map<Date, Map<MasterBean, ProcedureBean>> map = new HashMap<Date, Map<MasterBean, ProcedureBean>>();
		List<Date> dates = getWorkSchedule(date);
		
		List<MasterBean> masters = DBUtils.getInstance().getWorkingMastersForDay(date);
		List<ProcedureBean> procedures = DBUtils.getInstance().loadProcedures(date);
		
		if ((masters == null) || (masters.size() == 0)) {
			for(Date d : dates) {
				map.put(d, null);
			}
		}
		else {
			for(int i = 0; i < dates.size() - 1; i ++) {
				Map<MasterBean, ProcedureBean> mapProc = new HashMap<MasterBean, ProcedureBean>();
				for (MasterBean master : masters) {
					mapProc.put(master, getProcedures(procedures, master.getId(), dates.get(i), dates.get(i + 1)));
				}
				map.put(dates.get(i), mapProc);
			}
		}
		return map;
	}
	
	public List<Date> getWorkSchedule(Date date) {
		List<Date> dates = new ArrayList<Date>();
		Calendar d = Calendar.getInstance();
		d.setTime(date);
		d.set(Calendar.MINUTE, 0);
		d.set(Calendar.SECOND, 0);
		d.set(Calendar.MILLISECOND, 0);
		
		for (int i = 9; i < 23; i ++) {
			d.set(Calendar.HOUR_OF_DAY, i);
			dates.add(d.getTime());
		}
		
		return dates;
	}
	
	public ProcedureBean getProcedures(List<ProcedureBean> procedures, int masterId, Date sdate, Date fdate) {
		for (ProcedureBean bean : procedures) {
			if (bean.getMasterId() == masterId && 
					bean.getDate().getTime() >= sdate.getTime() && 
					bean.getDate().getTime() < fdate.getTime()) {
				return bean;
			}
		}
		return null;
	}
}
